#pragma once
#define TABLE_H

#include <string.h>

// 可用槽位总数，也正好是最大索引。减1是留给表头
#define TABLE_MAX_LEN (20017 - 1)
#define TABLE_MAX_INDEX (20017 - 1)

#define TABLE_HASH_BASE 31

struct KVpairs {
	void* val; // 指向值所在内存段的指针
	char* key; // 指向键所在内存段的指针
	int code; // +: 占用, 0: 空闲, -: 已解绑
}; // 键值对结构

typedef unsigned char byte;
typedef struct KVpairs kvp;
typedef kvp table[TABLE_MAX_LEN + 1]; // table只是一个普通的数组，不提供内存管理功能，键值对占用的内存需要自行准备

int hash(const void* bytes, size_t count); // 哈希函数
int tb_find(table, const char* key); // 查询键在表中的实际位置，返回位置或0

void* tb_get(table, const char* k); // 获取值的内存地址，不存在则返回NULL
int tb_set(table, const char* k, const void* v); // 设置值的内存地址，返回错误或0

int tb_pull(table, const char* k, char* v, size_t); // 从已经设置好的内存中拉取值的字符串副本
int tb_push(table, const char* k, const char* v); // 推送值的字符串副本到已经设置好的内存中

int kvp_unset(kvp*); // 将键值对设为解绑状态
int tb_del(table, const char* k); // 解绑一个键值对，以便这个空位可以容纳新的键值对
int tb_pop(table, const char* k, kvp*); // 解绑 的同时弹出一个副本

// void tb_clear(table); // 强制置零整个table
int tb_len(table); // 获取table长度
kvp* next(table, const kvp*); // 查找下一个键值对，没有了就返回NULL

// 适用于for遍历table
#define in_pairs(tb, kv) kv=next(tb,tb);kv;kv=next(tb,kv)


// 可选参数宏
#define __get5th(a, b, c, d, e, ...) e
#define __nparams(...) __get5th(__VA_ARGS__, 4, 3, 2, 1, 0)

#define __tb_pull_3(tb, key, val) tb_pull(tb, key, val, sizeof(val))
#define __tb_pull_4(tb, key, val, size) tb_pull(tb, key, val, size)
#define __tb_pull_cat(n, ...) __tb_pull_##n(__VA_ARGS__)
#define __tb_pull_expand(...) __tb_pull_cat(__VA_ARGS__)
#define tb_pull(...) __tb_pull_expand(__nparams(__VA_ARGS__), __VA_ARGS__)

#define __next_1(tb) next(tb, tb)
#define __next_2(tb, pair) next(tb, pair)
#define __next_cat(n, ...) __next_##n(__VA_ARGS__)
#define __next_expand(...) __next_cat(__VA_ARGS__)
#define next(...) __next_expand(__nparams(__VA_ARGS__), __VA_ARGS__)